#include <ios>
#include <ostream>
#include <sstream>
#include <string>
#include <unistd.h>
#include "Logger.h"

// self definde logger
static xncc::Logger timerLogger("stdout", xncc::LOG_LEVEL::DEBUG);
#define TIMER_LOG (timerLogger)

// self defined logger
static xncc::Logger logger;
#define DELAY_LOG (logger)

struct TrivalObjTest
{
    int a;
    int b;
    int c;
};

static xncc::LogObject& operator<<(xncc::LogObject& os, const TrivalObjTest& obj)
{
    os << "a:" << obj.a << " b:" << obj.b << " c:" << obj.c;
    return os;
}

constexpr int TEST_NUM_1 = 123;
constexpr int TEST_NUM_2 = 7777777;

int main(int /*argc*/, const char** /*argv*/)
{
    DELAY_LOG.Set("stdout", ".", 1024, xncc::LOG_LEVEL::DEBUG, -1);
    xncc::Logger::start();

    // log no args
    LOG_INFO(DELAY_LOG) << "this is a log no args with defined DELAY_LOG";
    LOG_INFO(CONSOLE_LOG) << "this is a log no args with defined CONSOLE_LOG";
    LOG_INFO(TIMER_LOG) << "this is a log no args with defined TIMER_LOG";

    // log with int args
    LOG_INFO(DELAY_LOG) << "this is a log with int args with defined DELAY_LOG " << TEST_NUM_1;
    LOG_INFO(CONSOLE_LOG) << "this is a log with int args with defined CONSOLE_LOG " << TEST_NUM_1;
    LOG_INFO(TIMER_LOG) << "this is a log with int args with defined TIMER_LOG " << TEST_NUM_1;

    // log with int variable args
    int a = TEST_NUM_1;
    LOG_INFO(DELAY_LOG) << "this is a log with int variable args with defined DELAY_LOG " << a;
    LOG_INFO(CONSOLE_LOG) << "this is a log with int variable args with defined CONSOLE_LOG " << a;
    LOG_INFO(TIMER_LOG) << "this is a log with int variable args with defined TIMER_LOG " << a;

    // log with unsigned int literal args
    LOG_INFO(DELAY_LOG) << "this is a log with unsigned int literal args with defined DELAY_LOG " << 123u;
    LOG_INFO(CONSOLE_LOG) << "this is a log with unsigned int literal args with defined CONSOLE_LOG " << 123u;
    LOG_INFO(TIMER_LOG) << "this is a log with unsigned int literal args with defined TIMER_LOG " << 123u;

    // log with unsigned int variable args
    unsigned int b = 123u;
    LOG_INFO(DELAY_LOG) << "this is a log with unsigned int variable args with defined DELAY_LOG " << b;
    LOG_INFO(CONSOLE_LOG) << "this is a log with unsigned int variable args with defined CONSOLE_LOG " << b;
    LOG_INFO(TIMER_LOG) << "this is a log with unsigned int variable args with defined TIMER_LOG " << b;

    // log with short literal args
    LOG_INFO(DELAY_LOG) << "this is a log with short literal args with defined DELAY_LOG " << TEST_NUM_1;
    LOG_INFO(CONSOLE_LOG) << "this is a log with short literal args with defined CONSOLE_LOG " << TEST_NUM_1;
    LOG_INFO(TIMER_LOG) << "this is a log with short literal args with defined TIMER_LOG " << TEST_NUM_1;

    // log with short variable args
    short c = TEST_NUM_1;
    LOG_INFO(DELAY_LOG) << "this is a log with short variable args with defined DELAY_LOG " << c;
    LOG_INFO(CONSOLE_LOG) << "this is a log with short variable args with defined CONSOLE_LOG " << c;
    LOG_INFO(TIMER_LOG) << "this is a log with short variable args with defined TIMER_LOG " << c;

    // log with unsigned short literal args
    LOG_INFO(DELAY_LOG) << "this is a log with unsigned short literal args with defined DELAY_LOG " << 123u;
    LOG_INFO(CONSOLE_LOG) << "this is a log with unsigned short literal args with defined CONSOLE_LOG " << 123u;
    LOG_INFO(TIMER_LOG) << "this is a log with unsigned short literal args with defined TIMER_LOG " << 123u;

    // log with unsigned short variable args
    unsigned short d = 123u;
    LOG_INFO(DELAY_LOG) << "this is a log with unsigned short variable args with defined DELAY_LOG " << d;
    LOG_INFO(CONSOLE_LOG) << "this is a log with unsigned short variable args with defined CONSOLE_LOG " << d;
    LOG_INFO(TIMER_LOG) << "this is a log with unsigned short variable args with defined TIMER_LOG " << d;

    // log with bool literal args
    LOG_INFO(DELAY_LOG) << "this is a log with bool literal args with defined DELAY_LOG " << true;
    LOG_INFO(CONSOLE_LOG) << "this is a log with bool literal args with defined CONSOLE_LOG " << true;
    LOG_INFO(TIMER_LOG) << "this is a log with bool literal args with defined TIMER_LOG " << true;

    // log with bool variable args
    bool e = true;
    LOG_INFO(DELAY_LOG) << "this is a log with bool variable args with defined DELAY_LOG " << e;
    LOG_INFO(CONSOLE_LOG) << "this is a log with bool variable args with defined CONSOLE_LOG " << e;
    LOG_INFO(TIMER_LOG) << "this is a log with bool variable args with defined TIMER_LOG " << e;

    // log with boolalpha variable args
    LOG_INFO(DELAY_LOG) << "this is a log with boolalpha variable args with defined DELAY_LOG " << std::boolalpha
                        << true << std::noboolalpha << " nonoboolalpha " << e;
    LOG_INFO(CONSOLE_LOG) << "this is a log with boolalpha variable args with defined CONSOLE_LOG " << std::boolalpha
                          << true << std::noboolalpha << " nonoboolalpha " << e;
    LOG_INFO(TIMER_LOG) << "this is a log with boolalpha variable args with defined TIMER_LOG " << std::boolalpha
                        << true << std::noboolalpha << " nonoboolalpha " << e;

    // log hex variable args
    LOG_INFO(DELAY_LOG) << "this is a log with hex variable args with defined DELAY_LOG " << std::hex << TEST_NUM_1
                        << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::oct << " oct " << TEST_NUM_1 << "-"
                        << TEST_NUM_2 << "-" << TEST_NUM_1 << std::dec << " nonhex " << TEST_NUM_1 << "-" << TEST_NUM_2
                        << "-" << TEST_NUM_1;
    LOG_INFO(CONSOLE_LOG) << "this is a log with hex variable args with defined CONSOLE_LOG " << std::hex << TEST_NUM_1
                          << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::oct << " oct " << TEST_NUM_1 << "-"
                          << TEST_NUM_2 << "-" << TEST_NUM_1 << std::dec << " nonhex " << TEST_NUM_1 << "-"
                          << TEST_NUM_2 << "-" << TEST_NUM_1;
    LOG_INFO(TIMER_LOG) << "this is a log with hex variable args with defined TIMER_LOG " << std::hex << TEST_NUM_1
                        << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::oct << " oct " << TEST_NUM_1 << "-"
                        << TEST_NUM_2 << "-" << TEST_NUM_1 << std::dec << " nonhex " << TEST_NUM_1 << "-" << TEST_NUM_2
                        << "-" << TEST_NUM_1;

    // log binary variable args
    LOG_INFO(DELAY_LOG) << "this is a log with binary variable args with defined DELAY_LOG " << std::binary
                        << TEST_NUM_1 << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::oct << " oct " << TEST_NUM_1
                        << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::dec << " nonhex " << TEST_NUM_1 << "-"
                        << TEST_NUM_2 << "-" << TEST_NUM_1;
    LOG_INFO(CONSOLE_LOG) << "this is a log with binary variable args with defined CONSOLE_LOG " << std::binary
                          << TEST_NUM_1 << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::oct << " oct " << TEST_NUM_1
                          << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::dec << " nonhex " << TEST_NUM_1 << "-"
                          << TEST_NUM_2 << "-" << TEST_NUM_1;
    LOG_INFO(TIMER_LOG) << "this is a log with binary variable args with defined TIMER_LOG " << std::binary
                        << TEST_NUM_1 << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::oct << " oct " << TEST_NUM_1
                        << "-" << TEST_NUM_2 << "-" << TEST_NUM_1 << std::dec << " nonhex " << TEST_NUM_1 << "-"
                        << TEST_NUM_2 << "-" << TEST_NUM_1;

    // log function args
    struct TrivalObj
    {
        int  a;
        int  b;
        int  c;
        void ToString(std::ostringstream& oss) const
        {
            oss << " member function a=" << a << " b=" << b << " c=" << c << " ";
        }
    };

    TrivalObj obj{};
    obj.a = 1;
    obj.b = 2;
    obj.c = 3;

    LOG_INFO(DELAY_LOG) << "this is a log with function args with defined DELAY_LOG "
                        << xncc::FUNCTION_OBJECT(obj, &TrivalObj::ToString);

    LOG_INFO(CONSOLE_LOG) << "this is a log with function args with defined CONSOLE_LOG "
                          << xncc::FUNCTION_OBJECT(obj, &TrivalObj::ToString);

    LOG_INFO(TIMER_LOG) << "this is a log with function args with defined TIMER_LOG "
                        << xncc::FUNCTION_OBJECT(obj, &TrivalObj::ToString);

    TrivalObjTest objTest{};
    objTest.a = 1;
    objTest.b = 2;
    objTest.c = 3;
    LOG_INFO(DELAY_LOG) << "this is a log with function args with defined DELAY_LOG " << objTest << " xxxxxxxx";
    LOG_INFO(CONSOLE_LOG) << "this is a log with function args with defined CONSOLE_LOG " << objTest << " xxxxxxxx";
    LOG_INFO(TIMER_LOG) << "this is a log with function args with defined TIMER_LOG " << objTest << " xxxxxxxx"_s;

    return 0;
}